package shira.seminar;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import lombok.Data;
import shira.person.Educative;
import shira.person.Ken.Mahoz;
import shira.seminar.deviations.AbstractDeviation;
import shira.sort.SortingScore;

/**
 * A POJO of a camp in the seminar.
 * 
 * @author avian
 */
@Data
public class Camp {

	/* --- Constructors --- */

	/**
	 * Constructs a new camp with an empty list of hugs.
	 * 
	 * @param name
	 *            Camp's name.
	 */
	public Camp(String name) {
		this(new ArrayList<Hug>(), name);
	}

	/**
	 * Constructs a new camp with the given name and hugs.
	 * 
	 * @param hugs
	 *            Camp's hugs.
	 * @param name
	 *            Camp's name.
	 */
	public Camp(List<Hug> hugs, String name) {
		super();
		this.hugs = hugs;
		this.name = name;
	}

	/* --- Object Impl. --- */

	@Override
	public String toString() {
		return getName();
	}

	/* --- Getters / Setters --- */

	/**
	 * Setter for the hugs. Calls <code>removeHug</code> for each hug on the old
	 * list, and then calls <code>addHug</code> for each hug on the new list.
	 * 
	 * @param hugs
	 *            The hugs to set.
	 */
	public void setHugs(List<Hug> hugs) {
		if (this.hugs != null) {
			for (Hug hug : this.hugs) {
				removeHug(hug);
			}
		}
		if (hugs != null) {
			for (Hug hug : hugs) {
				addHug(hug);
			}
		}
		this.hugs = hugs;
	}

	/**
	 * Adds a hug to the hugs list.
	 * 
	 * @param hug
	 *            The hug to add.
	 * @return Defined by {@link List#add(Object)}.
	 */
	public boolean addHug(Hug hug) {
		boolean returnValue = hugs.add(hug);
		hug.setCamp(this);
		return returnValue;
	}

	/**
	 * Removes a hug from the hugs list.
	 * 
	 * @param hug
	 *            The hug to remove.
	 * @return Defined by {@link List#remove(Object)}.
	 */
	public boolean removeHug(Hug hug) {
		hug.setCamp(null);
		return hugs.remove(hug);
	}

	/**
	 * Creates a list of all of the educatives from the camp's hugs, and returns
	 * it.
	 * 
	 * @return A list of all of the educatives in the camp.
	 */
	public List<Educative> getEducatives() {
		List<Educative> educatives = new ArrayList<Educative>();
		for (Hug hug : hugs) {
			educatives.addAll(hug.getEducatives());
		}
		return educatives;
	}

	/**
	 * @return A map between a string describing the deviation's origin and the
	 *         deviation.
	 */
	public Map<String, AbstractDeviation> calculateDeviations() {
		
		return null;
	}

	/* --- Public Methods --- */

	/**
	 * Calculates the camp's mahoz score.
	 * 
	 * @param score
	 *            The sorting score to use.
	 * @return The calculated score.
	 */
	public int calculateMahozScore(SortingScore score) {
		int mahozScore = score.getMahozScore();
		Map<Mahoz, Integer> educativesPerMahoz = calculateEducativesPerMahoz();
		int totalScore = 0;
		for (int mahozNumber : educativesPerMahoz.values()) {
			totalScore += Math.pow(mahozNumber, 2) * mahozScore;
		}
		return totalScore;
	}

	/* --- Private Methods --- */

	/**
	 * Calculates the number of educatives per mahoz in the camp.
	 * 
	 * @return A map between the mahoz and the number of educatives in it.
	 */
	private Map<Mahoz, Integer> calculateEducativesPerMahoz() {
		Map<Mahoz, Integer> educativesPerMahoz = new HashMap<Mahoz, Integer>();
		List<Educative> educatives = getEducatives();
		for (Educative educative : educatives) {
			Mahoz educativeMahoz = educative.getKen().getMahoz();
			Integer currentValue = educativesPerMahoz.get(educativeMahoz);
			if (currentValue == null) {
				currentValue = 1;
			} else {
				currentValue++;
			}
			educativesPerMahoz.put(educativeMahoz, currentValue);
		}
		return educativesPerMahoz;
	}

	/* --- Data Members --- */

	/** Camp's {@link Hug}s. */
	private List<Hug> hugs;

	/** Camp's name. */
	private String name;
}
